#ifndef BRIDGEOBJECTMANAGER_H
#define BRIDGEOBJECTMANAGER_H
#include <functional>
#include <QMetaMethod>
#include <QMetaObject>
#include <QObject>
#include <QPointer>

template<class T>
struct BridgeMethodTrait
{
    using F = QString (T::*)(const QString&, const QString&, const QString&, const QString&,
                             QWidget*);
};

template<class T>
struct BridgeMethodFilterTrait
{
    using F = bool (T::*)(const QString&, const QString&, const QString&, const QString&,
                          const QString&, QWidget*, QString&);
};

template<class T>
struct BridgeCallbackTrait
{
    using F = void (T::*)(const QString&, bool);
};

template<class T>
struct BridgeCallbackFilterTrait
{
    using F = bool (T::*)(const QString&, const QString&, bool);
};

template<class T>
struct BridgeEventTrait
{
    using F = void (T::*)(const QString&);
};

template<class T>
struct BridgeEventFilterTrait
{
    using F = bool (T::*)(const QString&, const QString&, const QString&);
};

class BridgeMethod
{
public:
    using F = std::function<QString(const QString&, const QString&, const QString&, const QString&,
                                    QWidget*)>;

    BridgeMethod() { }

    template<class T>
    BridgeMethod(T* obj, typename BridgeMethodTrait<T>::F f) : is_qo_f_(true), obj_(obj)
    {
        f_ = std::bind(f, obj, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
                       std::placeholders::_4, std::placeholders::_5);
    }
    explicit BridgeMethod(const F& f) : is_qo_f_(false), f_(f) { }

    QString operator()(const QString& args, const QString& success_callback,
                       const QString& failure_callback, const QString& sender_id,
                       QWidget* sender_view) const
    {
        if ((!is_qo_f_ && f_) || (is_qo_f_ && obj_)) {
            return f_(args, success_callback, failure_callback, sender_id, sender_view);
        }
        return QString();
    }

private:
    bool is_qo_f_;
    QPointer<QObject> obj_;
    F f_;
};

class BridgeMethodFilter
{
public:
    using F = std::function<bool(const QString&, const QString&, const QString&, const QString&,
                                 const QString&, QWidget*, QString&)>;

    BridgeMethodFilter() { }

    template<class T>
    BridgeMethodFilter(T* obj, typename BridgeMethodFilterTrait<T>::F f) : is_qo_f_(true), obj_(obj)
    {
        f_ = std::bind(f, obj, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
                       std::placeholders::_4, std::placeholders::_5, std::placeholders::_6,
                       std::placeholders::_7);
    }
    explicit BridgeMethodFilter(const F& f) : is_qo_f_(false), f_(f) { }

    bool operator()(const QString& method, const QString& args, const QString& success_callback,
                    const QString& failure_callback, const QString& sender_id, QWidget* sender_view,
                    QString& ret) const
    {
        if ((!is_qo_f_ && f_) || (is_qo_f_ && obj_)) {
            return f_(method, args, success_callback, failure_callback, sender_id, sender_view,
                      ret);
        }
        return false;
    }

    bool isValid() const { return ((!is_qo_f_ && f_) || (is_qo_f_ && obj_)); }

private:
    bool is_qo_f_;
    QPointer<QObject> obj_;
    F f_;
};

class BridgeCallback
{
public:
    using F = std::function<void(const QString&, bool keep)>;

    BridgeCallback() { }

    template<class T>
    BridgeCallback(T* obj, typename BridgeCallbackTrait<T>::F f) : is_qo_f_(true), obj_(obj)
    {
        f_ = std::bind(f, obj, std::placeholders::_1, std::placeholders::_2);
    }
    explicit BridgeCallback(const F& f) : is_qo_f_(false), f_(f) { }

    void operator()(const QString& args, bool keep = false) const
    {
        if ((!is_qo_f_ && f_) || (is_qo_f_ && obj_)) {
            f_(args, keep);
        }
    }

private:
    bool is_qo_f_;
    QPointer<QObject> obj_;
    F f_;
};

class BridgeCallbackFilter
{
public:
    using F = std::function<bool(const QString&, const QString&, bool)>;

    BridgeCallbackFilter() { }

    template<class T>
    BridgeCallbackFilter(T* obj, typename BridgeCallbackFilterTrait<T>::F f)
        : is_qo_f_(true), obj_(obj)
    {
        f_ = std::bind(f, obj, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
    }
    explicit BridgeCallbackFilter(const F& f) : is_qo_f_(false), f_(f) { }

    bool operator()(const QString& callback, const QString& args, bool keep = false) const
    {
        if ((!is_qo_f_ && f_) || (is_qo_f_ && obj_)) {
            return f_(callback, args, keep);
        }
        return false;
    }

    bool isValid() const { return ((!is_qo_f_ && f_) || (is_qo_f_ && obj_)); }

private:
    bool is_qo_f_;
    QPointer<QObject> obj_;
    F f_;
};

class BridgeEvent
{
public:
    using F = std::function<void(const QString&)>;

    BridgeEvent() { }

    template<class T>
    BridgeEvent(T* obj, typename BridgeEventTrait<T>::F f) : is_qo_f_(true), obj_(obj)
    {
        f_ = std::bind(f, obj, std::placeholders::_1);
    }
    explicit BridgeEvent(const F& f) : is_qo_f_(false), f_(f) { }

    void operator()(const QString& args) const
    {
        if ((!is_qo_f_ && f_) || (is_qo_f_ && obj_)) {
            f_(args);
        }
    }

private:
    bool is_qo_f_;
    QPointer<QObject> obj_;
    F f_;
};

class BridgeEventFilter
{
public:
    using F = std::function<bool(const QString&, const QString&, const QString&)>;

    BridgeEventFilter() { }

    template<class T>
    BridgeEventFilter(T* obj, typename BridgeEventFilterTrait<T>::F f) : is_qo_f_(true), obj_(obj)
    {
        f_ = std::bind(f, obj, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
    }
    explicit BridgeEventFilter(const F& f) : is_qo_f_(false), f_(f) { }
    bool operator()(const QString& source, const QString& name, const QString& args) const
    {
        if ((!is_qo_f_ && f_) || (is_qo_f_ && obj_)) {
            return f_(source, name, args);
        }
        return false;
    }

    bool isValid() const { return ((!is_qo_f_ && f_) || (is_qo_f_ && obj_)); }

private:
    bool is_qo_f_;
    QPointer<QObject> obj_;
    F f_;
};

class BridgeObject
{
public:
    BridgeObject() { }

    // 返回方法过滤器
    const BridgeMethodFilter& methodFilter() const { return method_filter_; }
    // 返回事件过滤器
    const BridgeEventFilter& eventFilter() const { return event_filter_; }
    // 返回回调过滤器
    const BridgeCallbackFilter& callbackFilter() const { return callback_filter_; }
    // 返回注册的方法
    const QHash<QString, BridgeMethod>& methods() const { return methods_; }
    // 返回注册的回调
    const QHash<QString, BridgeCallback>& callbacks() const { return callbacks_; }
    // 返回注册的事件处理器
    const QHash<QString, BridgeEvent>& events() const { return events_; }

    // 设置方法过滤器
    void setMethodFilter(const BridgeMethodFilter& f) { method_filter_ = f; }

    // 设置事件过滤器
    void setEventFilter(const BridgeEventFilter& f) { event_filter_ = f; }

    // 设置回调过滤器
    void setCallbackFilter(const BridgeCallbackFilter& f) { callback_filter_ = f; }

    // 注册方法
    void registerMethod(const QString& name, const BridgeMethod& method)
    {
        methods_.insert(name, method);
    }

    // 注销方法
    void unregisterMethod(const QString& name) { methods_.remove(name); }

    // 注册事件处理器
    void registerEvent(const QString& name, const BridgeEvent& event)
    {
        events_.insert(name, event);
    }

    // 注销事件处理器
    void unregisterEvent(const QString& name) { events_.remove(name); }

    // 注册回调
    void registerCallback(const QString& name, const BridgeCallback& callback)
    {
        callbacks_.insert(name, callback);
    }

    // 注销回调
    void unregisterCallback(const QString& name) { callbacks_.remove(name); }

private:
    BridgeMethodFilter method_filter_;
    BridgeEventFilter event_filter_;
    BridgeCallbackFilter callback_filter_;
    QHash<QString, BridgeMethod> methods_;
    QHash<QString, BridgeEvent> events_;
    QHash<QString, BridgeCallback> callbacks_;
};

class BridgeObjectManager
{
public:
    explicit BridgeObjectManager(const QString& framework_name);
    virtual ~BridgeObjectManager() { }

    // 返回框架的名称
    const QString& frameworkName() const { return framework_name_; }

    // 返回框架对象
    BridgeObject framework() const { return objects_.value(framework_name_); }

    // 设置方法名映射表
    const QHash<QString, QString>& methodMappingTable() const;
    void setMethodMappingTable(const QHash<QString, QString>& table);

    // 注册對象
    void registerObject(const QString& id, const BridgeObject& obj);

    // 取消注冊的對象
    void unregisterObject(const QString& id);

    // 返回所有注册的对象
    const QHash<QString, BridgeObject>& objects() const { return objects_; }

    // 返回是否包含指定的对象
    bool contains(const QString& id) const { return objects_.contains(id); }

    // 返回指定的对象
    BridgeObject object(const QString& id) const { return objects_.value(id); }

    // 调用回调, uniform_callback由object id和callback组成，形如Live.callback_1
    void invokeCallback(const QString& uniform_callback, const QString& args);

    // 统一的对象ID
    static QString uniformObjectId(const QString& object, const QString& id);

    // 分解统一的对象ID
    static bool resolveUniformObjectId(const QString& object_id, QString& object, QString& id);

    // 生成唯一的桥对象ID
    static QString bridgeObjectId();

private:
    const QString framework_name_;
    QHash<QString, QString> method_mapping_table_;
    QHash<QString, BridgeObject> objects_;
};

inline const QHash<QString, QString>& BridgeObjectManager::methodMappingTable() const
{
    return method_mapping_table_;
}

inline void BridgeObjectManager::setMethodMappingTable(const QHash<QString, QString>& table)
{
    method_mapping_table_ = table;
}

#endif // BRIDGEOBJECTMANAGER_H
